home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 8614 / 8614.xpi / modules / utils / ScriptManager.jsm < prev    next >
Text File  |  2010-02-10  |  10KB  |  355 lines

  1. // DO NOT import this into the global namespace, but instead
  2. // import it into your own namespace wrapper
  3.  
  4. var EXPORTED_SYMBOLS = ["SCRIPT_MANAGER"];
  5.  
  6. Components.utils.import("resource://glydo/utils/prototype_xul_1_6_0_3_modified.jsm");
  7. Components.utils.import("resource://glydo/utils/io.jsm");
  8. Components.utils.import("resource://glydo/utils/Utils.jsm");
  9. Components.utils.import("resource://glydo/utils/Prefs.jsm");
  10. Components.utils.import("resource://glydo/utils/Events.jsm");
  11. Components.utils.import("resource://glydo/ClientInfo.jsm");
  12.  
  13. var ScriptManager = Prototype.Class.create(EventSource,{
  14.     initialize: function($super) {
  15.         $super();
  16.         this.remoteResourcesVersion = 0;
  17.         this.remoteResources = {};
  18.         this.localScripts = {};
  19.         this.timedSyncCallback = Prototype.F.bind(this.syncRemoteResources,this);
  20.         this.syncTimer = null;
  21.         this.loadScripts();
  22.         var me = this;
  23.         this.fixedGlobalFunctions = {
  24.                 SM_dump: function(s) { me.dump(s); },
  25.         };
  26.     },
  27.  
  28.     getResource: function(name) {
  29.         return this.remoteResources[name];
  30.     },
  31.  
  32.     getScript: function(name) {
  33.         return this.localScripts[name] || this.getResource("scripts/" + name + ".js");
  34.     },
  35.  
  36.     loadScripts: function() {
  37.         var loaded = this.loadRemoteResourcesCache();
  38.         // Start synchronizing with the remote repository
  39.         this.syncRemoteResources();
  40.         
  41.         this.fire("onResourcesUpdated");
  42.     },
  43.  
  44.     loadRemoteResourcesCache: function() {
  45.         var failed = true;
  46.         try {
  47.             // Load remote resources cache
  48.             file = DirIO.get("ProfD");
  49.             file.append("glydo");
  50.             DirIO.create(file);
  51.             file.append("resources");
  52.             DirIO.create(file);
  53.             file.append("remote_resources.json");
  54.             
  55.             var json = FileIO.read(file);
  56.             if (json !== false) {
  57.                 var cache = Prototype.S.decodeJSON(json);
  58.                 this.remoteResourcesVersion = cache.version;
  59.                 this.remoteResources = cache.resources;
  60.                 failed = false;
  61.             }
  62.         } catch (ex) {
  63.             
  64.             if (window.Components) {
  65.                 Components.utils.reportError(ex);
  66.             }
  67.         }
  68.         if (failed) {
  69.             this.remoteResourcesVersion = 0;
  70.             this.remoteResources = {};
  71.         }
  72.         return !failed;
  73.     },
  74.     
  75.     saveRemoteResourcesCache: function() {
  76.         // Note that multiple simultaneous saves may corrupt
  77.         // the file. We should probably move to a model
  78.         // that is more tolerant to concurrency scenarios.
  79.         // We deal with corrupt files in the load cache
  80.         // method.
  81.         var failed = true;
  82.         
  83.         var contents = Prototype.O.toJSON({
  84.             version: this.remoteResourcesVersion,
  85.             resources: this.remoteResources
  86.         });
  87.            
  88.         try {
  89.             // Save remote resources cache
  90.             var file = DirIO.get("ProfD");
  91.             file.append("glydo");
  92.             DirIO.create(file);
  93.             file.append("resources");
  94.             DirIO.create(file);
  95.             file.append("remote_resources.json");
  96.             FileIO.create(file);
  97.             if (!FileIO.write(file,contents)) {
  98.                 throw "Can't store remote resources cache\n";
  99.             }
  100.             failed = false;
  101.         } catch (ex) {
  102.             
  103.             if (window.Components) {
  104.                 Components.utils.reportError(ex);
  105.             }
  106.         }
  107.         return !failed;
  108.     },
  109.  
  110.     syncRemoteResources: function() {
  111.         var params = ({
  112.             updated_since: this.remoteResourcesVersion,
  113.             clientVersion: CLIENT_INFO.version
  114.         });
  115.         if (this.syncTimer !== null) {
  116.             Utils.clearTimeout(this.syncTimer);
  117.             this.syncTimer = null;
  118.         }
  119.         this.syncTimer = Utils.setTimeout(this.timedSyncCallback,Prefs.resources_repository_sync_interval_millis);
  120.         new Prototype.Ajax.Request(
  121.                 Prefs.resources_repository_url, {
  122.                 method: 'get',
  123.                 parameters: params,
  124.                 onSuccess: Prototype.F.bind(this.onGetRemoteResourcesSuccess,this),
  125.                 onFailure: Prototype.F.bind(this.onAjaxFailure,this)
  126.             });
  127.     },
  128.     
  129.     onAjaxFailure: function(response) {
  130.         var reason = response ? response.responseText : "Communication problem";
  131.         if (!reason) {
  132.             reason = "Communication problem";
  133.         }
  134.         
  135.     },
  136.  
  137.     onGetRemoteResourcesSuccess: function(response) {
  138.         if (!response || (response.status == 0)) {
  139.             this.onAjaxFailure(response);
  140.             return;
  141.         }
  142.         
  143.         // We first store the result in memory
  144.         var result = response.responseJSON;
  145.         if (result) {
  146.             var updatedResources = [];
  147.             var newVersion = result.version || 0;
  148.             for (var n in result.updates) {
  149.                 if (!Prototype.S.startsWith(n,".")) {
  150.                     var o = result.updates[n];
  151.                     if (o === null || o === undefined) {
  152.                         
  153.                         delete this.remoteResources[n];
  154.                     } else {
  155.                         
  156.                         this.remoteResources[n] = o;
  157.                     }
  158.                     updatedResources.push(n);
  159.                 }
  160.             }
  161.             
  162.             this.remoteResourcesVersion = newVersion;
  163.             if (updatedResources.length > 0) {
  164.                 this.fire("onResourcesUpdated",updatedResources);
  165.                 // We save the remote resources in the local cache
  166.                 this.saveRemoteResourcesCache();
  167.             }
  168.         }
  169.     },
  170.     
  171.  
  172.     
  173.  
  174.     getSandbox: function(doc) {
  175.         return new ScriptManager.Sandbox(this,doc);
  176.     },
  177.     
  178.     invoke: function(doc,name,options,callbacks,libs) {
  179.         var sandbox = this.getSandbox(doc);
  180.         sandbox.invoke(name,options,callbacks,libs);
  181.     },
  182.  
  183.     dump: function(s) {
  184.         
  185.     },
  186. });
  187.  
  188. ScriptManager.Sandbox = Prototype.Class.create({
  189.     initialize: function(scriptManager,doc) {
  190.         this.scriptManager = scriptManager;
  191.         this.document = doc;
  192.         var unsafeWindow = doc.defaultView;
  193.         
  194.         if (unsafeWindow.wrappedJSObject) {
  195.             unsafeWindow = unsafeWindow.wrappedJSObject;
  196.         }
  197.         
  198.         this.window = new XPCNativeWrapper(unsafeWindow);
  199.         this.sandbox = Components.utils.Sandbox(this.window);
  200.         this.sandbox.window = this.window;
  201.         this.sandbox.unsafeWindow = this.window.wrappedJSObject;
  202.         this.sandbox.document = this.window.document;
  203.         this.sandbox.__proto__ = this.sandbox.window;
  204.         this.sandbox.Func = {};
  205.         this.sandbox.__callbacks = {};
  206.         
  207.         //this.sandbox = new XPCSafeJSObjectWrapper(this.sandbox);
  208.         
  209.         this.imports = {};
  210.         this.importEnv(doc);
  211.     },
  212.  
  213.     exec: function(name) {
  214.         var code = this.scriptManager.getScript(name);
  215.         if (!code) {
  216.             throw new Error("No code for script id '" + name + "'");
  217.         }
  218.         try {
  219.             Components.utils.evalInSandbox(code,this.sandbox);
  220.         } catch (e) {
  221.             var msg = (typeof e == "string") ? e : (e.name + ": " + e.message);
  222.             msg = msg + " (while executing " + name + ")";
  223.             throw new Error(msg,name,0);
  224.         }
  225.     },
  226.     
  227.     importScript: function(name) {
  228.         // If script was already dynamically imported, don't import it again. Otherwise
  229.         // we import it
  230.         var imported = this.imports[name];
  231.         if (imported && imported.type == "dynamic") {
  232. //            
  233.             return;
  234.         }
  235.         // Get code
  236.         var code = this.scriptManager.getScript(name);
  237.         if (!code) {
  238.             if (imported) {
  239. //                
  240.                 return;
  241.             }
  242.             throw new Error("No code for script id '" + name + "'");
  243.         }
  244.         
  245.         var escName = name.toSource();
  246. //        
  247.         try {
  248.             Components.utils.evalInSandbox("Func[" + escName + "] = function(options,callbacks){"+code+"};",this.sandbox);
  249.         } catch (e) {
  250.             var msg = (typeof e == "string") ? e : (e.name + ": " + e.message);
  251.             msg = msg + " (while importing " + name + ")";
  252.             throw new Error(msg,name,0);
  253.         }
  254.         this.imports[name] = {
  255.                 type: "dynamic"
  256.         };
  257.     },
  258.  
  259.     importBuiltinLibraries: function(libs) {
  260.         for (var l = 0; l < libs.length; ++l) {
  261.             this.importBuiltinLibrary(libs[l]);
  262.         }
  263.     },
  264.     
  265.     importBuiltinLibrary: function(library) {
  266.         for (var name in library) {
  267.             this.importBuiltinScript(name,library[name]);
  268.         }
  269.     },
  270.     
  271.     importBuiltinScript: function(name,func) {
  272.         if (this.imports[name]) {
  273. //            
  274.             return;
  275.         }
  276.         // Import function
  277.         var globName = "__SM_import_" + name.replace(/[^a-zA-Z_0-9]/g,"_");
  278.         var me = this;
  279.         this.sandbox.importFunction(function(options,callbacks) {
  280.             return func(me,options,callbacks);
  281.         },globName);
  282.         var escName = name.toSource();
  283. //        
  284.         Components.utils.evalInSandbox("Func[" + escName + "] = " + globName + ";",this.sandbox);
  285.         this.imports[name] = {
  286.                 type: "builtin",
  287.                 func: func
  288.         };
  289.     },
  290.     
  291.     importCallbacks: function(callbacks) {
  292.         Components.utils.evalInSandbox("__callbacks = {};",this.sandbox);
  293.         if (callbacks) {
  294.             for (var p in callbacks) {
  295.                 var cbname = "__SM_callback_" + p;
  296.                 this.sandbox.importFunction(callbacks[p],cbname);
  297.                 Components.utils.evalInSandbox("__callbacks[" + p.toSource() + "]=" + cbname + ";\n" + cbname + "=undefined;",this.sandbox);
  298.             }
  299.         }
  300.     },
  301.  
  302.     importEnv: function() {
  303.         this.importFixedFunctions();
  304.         var me = this;
  305.         // The import function imports into the current sandbox
  306.         this.sandbox.importFunction(function(name) {
  307.             me.importScript(name);
  308.         },"SM_import");
  309.         this.sandbox.importFunction(function(name) {
  310.             me.exec(name);
  311.         },"SM_exec");
  312. //        var win = doc.defaultView;
  313. //        var origin = win.location.protocol + "//" + win.location.host;
  314. //        this.sandbox.importFunction(function(eventType,data) {
  315. //            var evt = doc.createEvent("MessageEvents");
  316. //            evt.initMessageEvent(eventType, true, false, data, origin,null,win);  
  317. //            win.dispatchEvent(evt);
  318. //        },"SM_message");
  319.     },
  320.     
  321.     importFixedFunctions: function() {
  322.         for (var p in this.scriptManager.fixedGlobalFunctions) {
  323.             this.sandbox.importFunction(this.scriptManager.fixedGlobalFunctions[p],p);
  324.         }
  325.     },
  326.     
  327.     invoke: function(name,options,callbacks,libs) {
  328.         // We only allow JSON-able options to be passed into scripts, for
  329.         // security purposes
  330.         options = options || {};
  331.         var optionsJSON = Prototype.O.toJSON(options);
  332.         if (libs) {
  333.             this.importBuiltinLibraries(libs);
  334.         }
  335.         this.importScript(name);
  336.         this.importCallbacks(callbacks);
  337.         var imported = this.imports[name];
  338.         if (imported.type == "builtin") {
  339.             imported.func(this,options,callbacks);
  340.         } else {
  341.             try {
  342.                 Components.utils.evalInSandbox(
  343.                     "(function(){return Func[" + name.toSource() + "]((" + optionsJSON + "),__callbacks);})()",
  344.                     this.sandbox);
  345.             } catch (e) {
  346.                 var msg = (typeof e == "string") ? e : (e.name + ": " + e.message);
  347.                 msg = msg + " (while executing " + name + ")";
  348.                 throw new Error(msg,name,0);
  349.             }
  350.         }
  351.     },
  352. }); 
  353.  
  354. var SCRIPT_MANAGER = new ScriptManager();
  355.